home *** CD-ROM | disk | FTP | other *** search
/ HyperLib 1997 Winter - Disc 1 / HYPERLIB-1997-Winter-CD1.ISO.7z / HYPERLIB-1997-Winter-CD1.ISO / オンラインウェア / PRG / MacPerl 506 appl folder.sit / MacPerl 506 appl folder / Mac_Perl_506r1m_appl / lib / macftp.pl < prev    next >
Perl Script  |  1993-10-23  |  10KB  |  416 lines

  1. #!/usr/local/bin/perl
  2. #   This is a set of ftp library routines using chat2.pl
  3. #   Return code information taken from RFC 959
  4.  
  5. #   Written by Gene Spafford  <spaf@cs.purdue.edu>
  6. #       Last update: 10 April 92,   Version 0.9
  7. #
  8.  
  9. # put() and port to MacPerl M. Neeracher <neeri@iis.ethz.ch>
  10.  
  11. #
  12. #   Most of these routines communicate over an open ftp channel
  13. #   The channel is opened with the "ftp'open" call.
  14. #
  15.  
  16. package ftp;
  17. require "macchat.pl";
  18. require "GUSI.ph";
  19.  
  20. ###########################################################################
  21. #
  22. #  The following are the variables local to this package.
  23. #  I declare them all up front so I can remember what I called 'em. :-)
  24. #
  25. ###########################################################################
  26.  
  27. LOCAL_VARS: {    
  28.     $Control;
  29.     $Data_handle;
  30.     $Host;
  31.     $Myhost = "Some.Poor.Mac";
  32. # Currently no way to do gethostname
  33.     $NeedsCleanup;
  34.     $NeedsClose;
  35.     $ftp_error;
  36.     $ftp_matched;
  37.     $ftp_trans_flag;
  38.     $ftp_echo;
  39.     @ftp_list;
  40.  
  41.     local(@tmp) = getservbyname("ftp", "tcp");
  42.     ($FTP = $tmp[2]) || 
  43.     die "Unable to get service number for 'ftp' (in ftplib)!¥n";
  44.  
  45.     @std_actions = (
  46.         'TIMEOUT',
  47.         q($ftp_error = "Connection timed out for $Host!¥n"; undef),
  48.         'EOF', 
  49.         q($ftp_error = "Connection to $Host timed out unexpectedly!¥n"; undef)
  50.     );
  51.  
  52.     @sigs = ('INT', 'HUP', 'TERM', 'QUIT');  # sigs we'll catch & terminate on
  53. }
  54.  
  55.  
  56.  
  57. ###########################################################################
  58. #
  59. #  The following are intended to be the user-callable routines.
  60. #  Each of these does one of the ftp keyword functions.
  61. #
  62. ###########################################################################
  63.  
  64. sub error { ## Public
  65.     $ftp_error;
  66. }
  67.  
  68. sub echo { ## Public
  69.     ($ftp_echo) = @_;
  70. }
  71.   
  72. #######################################################
  73.  
  74. #   cd up a directory level
  75.  
  76. sub cdup { ## Public
  77.     &do_ftp_cmd(200, "cdup");
  78. }
  79.  
  80. #######################################################
  81.  
  82. # close an open ftp connection
  83.  
  84. sub close { ## Public
  85.     return unless $NeedsClose;
  86.     &do_ftp_cmd(221, "quit");
  87.     &macchat'close($Control);
  88.     undef $NeedsClose;
  89.     &do_ftp_signals(0);
  90. }
  91.  
  92. #######################################################
  93.  
  94. # change remote directory
  95.  
  96. sub cwd { ## Public
  97.     &do_ftp_cmd(250, "cwd", @_);
  98. }
  99.   
  100. #######################################################
  101.  
  102. #  delete a remote file
  103.  
  104. sub delete { ## Public
  105.      &do_ftp_cmd(250, "dele", @_); 
  106. }
  107.  
  108. #######################################################
  109.  
  110. #  get a directory listing of remote directory ("ls -l")
  111.  
  112. sub dir { ## Public
  113.     &do_ftp_listing("list", @_);
  114. }
  115.  
  116. #######################################################
  117.  
  118. #  get a remote file to a local file
  119. #    get(remote[, local])
  120.  
  121. sub get { ## Public
  122.     local($remote, $local) = @_;
  123.     ($local = $remote) unless $local;
  124.  
  125.     unless (open(DFILE, ">$local")) {
  126.     $ftp_error =  "Open of local file $local failed: $!";
  127.     return undef;
  128.     } else {
  129.     $NeedsCleanup = $local;
  130.     }
  131.  
  132.     return undef unless &do_open_dport;     # Open a data channel
  133.     unless (&do_ftp_cmd(150, "retr $remote")) {
  134.     $ftp_error .= "¥nFile $remote not fetched from $Host¥n";
  135.     close DFILE;
  136.     unlink $local;
  137.     undef $NeedsCleanup;
  138.     return;
  139.     }
  140.  
  141.     $ftp_trans_flag = 0;
  142.  
  143.     do {
  144.     &macchat'expect($Data_handle, 60,
  145.              '.|¥n', q{$macchat'thisbuf =~ s|¥015¥012|¥n|g;
  146.                                print DFILE ($macchat'thisbuf) ||
  147.             ($ftp_trans_flag = 3); undef $macchat'S},
  148.              'EOF',  '$ftp_trans_flag = 1',
  149.              'TIMEOUT', '$ftp_trans_flag = 2');
  150.     } until $ftp_trans_flag;
  151.  
  152.     close DFILE;
  153.     &macchat'close($Data_handle);        # Close the data channel
  154.  
  155.     undef $NeedsCleanup;
  156.     if ($ftp_trans_flag > 1) {
  157.     unlink $local;
  158.     $ftp_error = "Unexpected " . ($ftp_trans_flag == 2 ? "timeout" :
  159.         ($ftp_trans_flag != 3 ? "failure" : "local write failure")) .
  160.                 " getting $remote¥n";
  161.     }
  162.     
  163.     &do_ftp_cmd(226);
  164. }
  165.  
  166. #######################################################
  167.  
  168. #  put a local file to a remote file
  169. #    put(local[, remote])
  170.  
  171. sub put { ## Public
  172.     local($local, $remote) = @_;
  173.     ($remote = $local) unless $remote;
  174.  
  175.     unless (open(DFILE, "<$local")) {
  176.     $ftp_error =  "Open of local file $local failed: $!";
  177.     return undef;
  178.     } 
  179.  
  180.     return undef unless &do_open_dport;     # Open a data channel
  181.     unless (&do_ftp_cmd(150, "stor $remote")) {
  182.     $ftp_error .= "¥nFile $remote not stored on $Host¥n";
  183.     close DFILE;
  184.     return undef;
  185.     }
  186.  
  187.     &macchat'expect($Data_handle, 0);              # Force macchat to do an accept
  188.  
  189.     while (<DFILE>) {
  190.         chop;
  191.     &macchat'print($Data_handle, "$_¥015¥012");
  192.     }
  193.  
  194.     close DFILE;
  195.     &macchat'close($Data_handle);                # Close the data channel
  196.     
  197.     &do_ftp_cmd(226);
  198. }
  199.  
  200. #######################################################
  201.  
  202. #  Do a simple name list ("ls")
  203.  
  204. sub list { ## Public
  205.     &do_ftp_listing("nlst", @_);
  206. }
  207.  
  208. #######################################################
  209.  
  210. #   Make a remote directory
  211.  
  212. sub mkdir { ## Public
  213.     &do_ftp_cmd(257, "mkd", @_);
  214. }
  215.  
  216. #######################################################
  217.  
  218. #  Open an ftp connection to remote host
  219.  
  220. sub open {  ## Public
  221.     if ($NeedsClose) {
  222.     $ftp_error = "Connection still open to $Host!";
  223.     return undef;
  224.     }
  225.  
  226.     $Host = shift(@_);
  227.  
  228.     local($Port) = $FTP;
  229.  
  230.     if ($Host =~ /(.*)¥s+([0-9]+)/) {
  231.     ($Host, $Port) = ($1, $2);
  232.     }
  233.  
  234.     local($User, $Password, $Acct) = @_;
  235.     $User = "anonymous" unless $User;
  236.     $Password = "-" . $main'ENV{'USER'} . "@$Myhost" unless $Password;
  237.     $ftp_error = '';
  238.  
  239.     unless($Control = 
  240.         &macchat'open_port(
  241.         &GUSI'AF_INET, &GUSI'pack_sockaddr_in(&GUSI'AF_INET, $Host, $Port))) {
  242.     $ftp_error = "Unable to connect to $Host";
  243.     if ($Port == $FTP) {
  244.         $ftp_error .= " ftp port: $!";
  245.     } else {
  246.         $ftp_error .= " port $Port: $!";
  247.     }
  248.     return undef;
  249.     }
  250.  
  251.     unless(&macchat'expect($Control, 60,
  252.                 '^220 .*¥015¥012',    "1",
  253.                 '^¥d¥d¥d .*¥015¥012',      "undef")) {
  254.     $ftp_error = "Error establishing control connection to $Host";
  255.         &macchat'close($Control);
  256.     return undef;
  257.     }
  258.     &do_ftp_signals($NeedsClose = 1);
  259.  
  260.     unless (&do_ftp_cmd(331, "user $User")) {
  261.     $ftp_error .= "¥nUser command failed establishing connection to $Host";
  262.     return undef;
  263.     }
  264.  
  265.     unless (&do_ftp_cmd("(230|332|202)", "pass $Password")) {
  266.     $ftp_error .= "¥nPassword command failed establishing connection to $Host";
  267.     return undef;
  268.     }
  269.  
  270.     return 1 unless $Acct;
  271.  
  272.     unless (&do_ftp_cmd("(230|202)", "pass $Password")) {
  273.     $ftp_error .= "¥nAcct command failed establishing connection to $Host";
  274.     return undef;
  275.     }
  276.     1;
  277. }
  278.  
  279. #######################################################
  280.  
  281. #  Get name of current remote directory
  282.  
  283. sub pwd { ## Public
  284.     if (&do_ftp_cmd(257, "pwd")) {
  285.     $ftp_matched =~ m/^257 (.+)¥015?¥012/;
  286.     $1;
  287.     } else {
  288.     undef;
  289.     }    
  290. }
  291.  
  292. #######################################################
  293.  
  294. #  Rename a remote file
  295.  
  296. sub rename { ## Public
  297.     local($from, $to) = @_;
  298.  
  299.     &do_ftp_cmd(350, "rnfr $from") && &do_ftp_cmd(250, "rnto $to");
  300. }
  301.  
  302. #######################################################
  303.  
  304. #  Set transfer type
  305.  
  306. sub type { ## Public
  307.     &do_ftp_cmd(200, "type", @_); 
  308. }
  309.  
  310.  
  311. ###########################################################################
  312. #
  313. #  The following are intended to be utility routines used only locally.
  314. #  Users should not call these directly.
  315. #
  316. ###########################################################################
  317.  
  318. sub do_ftp_cmd {  ## Private
  319.     local($okay, @commands, $val) = @_;
  320.  
  321.     $ftp_echo && $commands[0] && 
  322.     print STDERR join(" ", @commands) . "¥015¥012";
  323.     $commands[0] && 
  324.     &macchat'print($Control, (join(" ", @commands) . "¥015¥012"));
  325.  
  326.     &macchat'expect($Control, 60, 
  327.          "^$okay .*¥¥015¥¥012",    'print STDERR $& if $ftp_echo;
  328.                      $ftp_matched = $&; 1',
  329.          "^(¥d)¥d¥d .*¥¥015¥¥012", '($String = $&) =~ y/¥015¥012//d;
  330.                      print STDERR $& if $ftp_echo;
  331.              $ftp_error = qq{Unexpected reply for ' .
  332.              "@commands" . ': $String}; 
  333.              $1 > 3 ? undef : 1',
  334.          @std_actions
  335.         );
  336. }
  337.  
  338. #######################################################
  339.  
  340. sub do_ftp_listing { ## Private
  341.     local(@lcmd) = @_;
  342.     @ftp_list = ();
  343.     $ftp_trans_flag = 0;
  344.  
  345.     return undef unless &do_open_dport;
  346.  
  347.     return undef unless &do_ftp_cmd(150, @lcmd);
  348.     do {            #  Following is grotty, but macchat2 makes us do it
  349.         &macchat'expect($Data_handle, 30,
  350.         '(.*¥n?¥012)',    'push(@ftp_list, $1)',
  351.         "EOF",     '$ftp_trans_flag = 1');
  352.     } until $ftp_trans_flag;
  353.  
  354.     &macchat'close($Data_handle);
  355.     return undef unless &do_ftp_cmd(226);
  356.  
  357.     grep(y/¥015¥012//d, @ftp_list);
  358.     @ftp_list;
  359. }  
  360.  
  361. #######################################################
  362.  
  363. sub do_open_dport { ## Private
  364.     local(@foo, $fam, $addr, $port) = &macchat'open_listen(&GUSI'AF_INET);
  365.     ($port, $Data_handle) = @foo;
  366.     ($fam,$addr,$port) = &GUSI'unpack_sockaddr_in($port);
  367.  
  368.     unless ($Data_handle) {
  369.     $ftp_error =  "Unable to open data port: $!";
  370.     return undef;
  371.     }
  372.  
  373.     $addr =~ tr/./,/;
  374.     @foo = ($port >> 8, $port & 0xff);
  375.     $addr .= "," . join(',', @foo);
  376.     
  377.     &do_ftp_cmd(200, "port $addr");
  378. }
  379.  
  380. #######################################################
  381. #
  382. #  To cleanup after a problem
  383. #
  384.  
  385. sub do_ftp_abort {
  386.     die unless $NeedsClose;
  387.  
  388.     &macchat'print($Control, "abor", "¥015¥012");
  389.     &macchat'close($Data_handle);
  390.     &macchat'expect($Control, 10, '.', undef);
  391.     &macchat'close($Control);
  392.  
  393.     close DFILE;
  394.     unlink($NeedsCleanup) if $NeedsCleanup;
  395.     die;
  396. }
  397.  
  398. #######################################################
  399. #
  400. #  To set signals to do the abort properly
  401. #
  402.  
  403. sub do_ftp_signals {
  404.     local($flag, $sig) = @_;
  405.  
  406.     local ($old, $new) = ('DEFAULT', "ftp'do_ftp_abort");
  407.     $flag || (($old, $new) = ($new, $old));
  408.     foreach $sig (@sigs) {
  409.     ($SIG{$sig} == $old) && ($SIG{$sig} = $new);
  410.     }
  411. }
  412.  
  413. 1;
  414.  
  415.